package servlets;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import controller.Course;
import controller.CourseSession;
import controller.Student;

import database.Connect;
import database.Queries;

/**
 * Servlet implementation class FeatureServlet
 */
public class FeatureServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FeatureServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String action=request.getParameter("action");
		if (action.equals("timeline")){
			showTimeLine(request,response);
			return;
		}	
	}
	
	/**
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	private void showTimeLine(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String xslType = request.getParameter("xsl");
		PrintWriter out=null;
		Document doc = null;
		try {
			out = response.getWriter();
			//generate XML for student
			doc = generateXML(request, response);
			if (doc==null){
				response.sendError(500);
				return;
			}
			//transform xml to html
			transformXML(response, xslType, out, doc);
			/* TransformerFactory transfac = TransformerFactory.newInstance();
	         try {
				Transformer trans = transfac.newTransformer();
				StringWriter sw = new StringWriter();
	            StreamResult result = new StreamResult(sw);
	            DOMSource source = new DOMSource(doc);
	            trans.transform(source, result);
	            String xmlString = sw.toString();
	            System.out.println(xmlString);
			} catch (TransformerConfigurationException e) {
				e.printStackTrace();
			} catch (TransformerException e) {
				e.printStackTrace();
			}*/
		} catch (IOException e) {
			response.sendError(500);
			e.printStackTrace();
			return;
		} catch (ParserConfigurationException e) {
			response.sendError(500);
			e.printStackTrace();
			return;
		} catch (SQLException e) {
			response.sendError(500);
			e.printStackTrace();
			return;
		} 
	}

	/**
	 * 
	 * @param response
	 * @param xslType
	 * @param out
	 * @param doc
	 * @throws TransformerFactoryConfigurationError
	 * @throws IOException
	 */
	private void transformXML(HttpServletResponse response, String xslType,
			PrintWriter out, Document doc)
			throws TransformerFactoryConfigurationError, IOException {
		
		StreamSource s = null;
		
		if (xslType.equals("1")){
			String webAppPath = getServletContext().getRealPath( "/templates/timeline1.xsl" );
			s = new StreamSource(webAppPath);
		}
		else if (xslType.equals("2")){
			String webAppPath = getServletContext().getRealPath( "/templates/timeline2.xsl" );
			s = new StreamSource(webAppPath);
		}
		else {
			s = new StreamSource(new ByteArrayInputStream(xslType.getBytes()));
		}
		//transform
		TransformerFactory tFactory = TransformerFactory.newInstance();
		try {
			Transformer transformer = tFactory.newTransformer(s);
			StringWriter sw = new StringWriter();
	        StreamResult result = new StreamResult(sw);
			transformer.transform(new DOMSource(doc),result);
			String htmlString = sw.toString();
			out.println(htmlString);
			return;
		} catch (TransformerConfigurationException e) {
			response.sendError(400);
			e.printStackTrace();
			return;
		} catch (TransformerException e) {
			response.sendError(400);
			e.printStackTrace();
			return;
		}
	}
	
	/**
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SQLException
	 * @throws IOException
	 */
	private Document generateXML(HttpServletRequest request,
			HttpServletResponse response) throws ParserConfigurationException, SQLException, IOException {
		
		
		DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
        Document doc = docBuilder.newDocument();
        Element root = doc.createElement("calendar");
        doc.appendChild(root);
        
        Connection conn = null;
        try {
			conn = Connect.getConnection();
			conn.setAutoCommit(false);
		    Student student = Queries.createStudent(conn, request.getUserPrincipal().getName());
		    if (student==null){
		    	response.sendError(500);
		    	return null;
		    }
		    LinkedList<Course> courses = student.getCourses();
		    for (Course currentCourse : courses){
		    	//course element
		    	Element courseDOM = doc.createElement("course");
		    	root.appendChild(courseDOM);
		    	//title for course
		    	Element titleDOM = doc.createElement("title");
		    	titleDOM.appendChild(doc.createTextNode(currentCourse.getName()));
		    	courseDOM.appendChild(titleDOM);
		    	//credit for course
		    	Element creditDOM = doc.createElement("credit");
		    	creditDOM.appendChild(doc.createTextNode(currentCourse.getPointNum().toString()));
		    	courseDOM.appendChild(creditDOM);
		    	//group number for course
		    	Element groupDOM = doc.createElement("gnumber");
		    	groupDOM.appendChild(doc.createTextNode(currentCourse.getGroupNum().toString()));
		    	courseDOM.appendChild(groupDOM);
		    	courseDOM = createSessionElements(doc,courseDOM,currentCourse); 	
		    } 
		    conn.commit();
		    return doc;   
		} catch (SQLException e) {
			conn.rollback();
			e.printStackTrace();
			throw e;
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		}
		finally {
			if (conn!=null){
				conn.setAutoCommit(true);
				conn.close();
			}
		}
	}
	
	/**
	 * 
	 * @param doc
	 * @param courseDOM
	 * @param currentCourse
	 * @return
	 */
	private Element createSessionElements(Document doc, Element courseDOM,
			Course currentCourse) {
		CourseSession[] sessions = currentCourse.getSessions();
		for (int i=0;i<sessions.length;i++){
			//create session element
			Element sessionDOM = doc.createElement("session");
			//create day
			Element dayDOM = doc.createElement("day");
			dayDOM.appendChild(doc.createTextNode(sessions[i].getDay()));
			sessionDOM.appendChild(dayDOM);
			//create start
			Element startDOM = doc.createElement("start");
			Integer start = sessions[i].getStart();
			startDOM.appendChild(doc.createTextNode(start.toString()));
			sessionDOM.appendChild(startDOM);
			//create End
			Element endDOM = doc.createElement("end");
			Integer end = sessions[i].getEnd();
			endDOM.appendChild(doc.createTextNode(end.toString()));
			sessionDOM.appendChild(endDOM);
			//append session to course
			courseDOM.appendChild(sessionDOM);
		}
		return courseDOM;
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request,response);
	}

}
